package design.demos.order;

import design.demos.order.bo.Order;
import design.demos.order.enums.StateEnum;
import design.demos.order.state.impl.OrderEnd;
import design.demos.order.state.impl.OrderPending;
import design.demos.order.state.impl.OrderProcessing;
import design.demos.order.service.OrderDataBaseService;
import design.demos.order.state.OrderState;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class StateHandler {
    OrderDataBaseService orderService = new OrderDataBaseService();

    Map<String, OrderState> orderStateMap = new HashMap<>();
    {
        orderStateMap.put(StateEnum.ORDER_PENDING.toString(), new OrderPending());
        orderStateMap.put(StateEnum.ORDER_PROCESSING.toString(), new OrderProcessing());
        orderStateMap.put(StateEnum.ORDER_END.toString(), new OrderEnd());
    }

    public Order stateHandler(Order order, StateEnum targetState) {
        Integer currentStateVal = null;
        if (null != order.getId()) {
            Order currentOrder = orderService.getOrderById(order.getId());
            currentStateVal = currentOrder.getState();
        }
        StateEnum currentState= StateEnum.getOrderState(currentStateVal);
        OrderState currentOrderState = orderStateMap.get(currentState.toString());
        OrderState targetOrderState = orderStateMap.get(targetState.toString());
        return invokeMethod(currentOrderState, targetOrderState,order);
    }


    /**
     * 通过反射调用从当前状态流转到目标状态的方法
     */
    public Order invokeMethod(OrderState currentOrderState, OrderState targetOrderState, Order order){
        try {
            Class<?> stateClass = currentOrderState.getClass();
            String targetClassName=targetOrderState.getClass().getSimpleName();
            String targetMethodName = Character.toLowerCase(targetClassName.charAt(0)) + targetClassName.substring(1);
            Method method = stateClass.getDeclaredMethod(targetMethodName, Order.class);
            return (Order) method.invoke(currentOrderState,order);
        } catch (NoSuchMethodException exception) {
            String errorMsg = currentOrderState.getClass().getSimpleName() + "-->" + targetOrderState.getClass().getSimpleName() + " 状态流转操作非法！";
            throw new RuntimeException(errorMsg);
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}
